fix(app-shell): drop the undeclared chart.config forward on the object-chart node (objectui#7891) - #7948
Merged
Conversation
…ect-chart node (objectui#7891) `ObjectView`'s dedicated chart-view route put `config: chartConfig.config` on the `object-chart` schema it builds, on both the ADR-0021 dataset branch and the legacy branch. `@objectstack/spec`'s `ListChartConfigSchema` is a `strictObject` declaring exactly `chartType` / `dataset` / `dimensions` / `values`, and objectui binds it by reference, so `config` is refused by name — `unrecognized_keys ["config"]` — by the same schema the platform's metadata write door parses every save through. The rung was a channel no conforming author could feed, landing on a node that does not declare `config` either. The `as any` on both literals was measured inert: `ObjectChart` is published as `(props: any)`, so the literals were checked against nothing. Removed with the rung. For every spec-conforming view this is a no-op. A non-conforming row degrades rather than breaks — `ChartRenderer` generates a container config from `series` plus a positional palette when none is present. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7891
Clause-②: noObjectView's dedicated chart-view route putconfig: chartConfig.configon theobject-chartschema it builds, on both branches —:2118(ADR-0021 dataset) and:2152(legacy). This drops both rungs, and the two
as anycasts that turned out to be inert.The card's premise was inverted before this PR, and the inversion is the fix
The card was filed as "
ListViewis missing aconfigrung that the dedicated chart routehas". The measurement that preceded this work reversed it:
ListViewis not missing achannel — app-shell had an extra one no author is allowed to feed.
@objectstack/spec@17.2.0'sListChartConfigSchemais astrictObjectwhose declaredkeys are exactly
chartType/dataset/dimensions/values, and objectui binds itBY REFERENCE (
chartis absent fromLIST_VIEW_LOCAL_OVERRIDES,packages/types/src/zod/objectql.zod.ts:312), soListViewSchema.chartIS the spec'sstrict schema. A view body carrying the key is refused by name.
So this was never one authored declaration rendering two ways. It was an asymmetry between
two UNDECLARED channels — and
ObjectChartSchemadoes not declareconfigeither, so thekey landed on a node that had no name for it.
The blocking measurement this dispatch required: can
chart.configreach STORED data?No — the write door refuses it, and no producer exists. Four readings:
The write door parses every save through the same schema.
saveMetaItem(objectstack packages/metadata-protocol/src/protocol.ts:15149) callsresolveOverlaySchema(type)togetMetadataTypeSchema('view')(
objectstack packages/spec/src/kernel/metadata-type-schemas.ts:110),safeParses, andanswers
422 INVALID_METADATAon failure. There is no early return between the modefold and that gate, and the gate reads neither
modenorforce— so it runs onmode: 'draft'(what app-shell'spersistRuntimeMetadatasends) exactly as on publish.Run against the published spec build this repo resolves, from inside its real dependency
graph:
The authoring UIs cannot mint it.
ViewConfigPanelhosts the studio'sViewVariantInspector, which renders the per-view-type fields straight from@objectstack/spec;CreateViewDialog'schartfield list ischartType/xAxisField/yAxisFields.view-config-adapterround-trips unknown keys, so it wouldPRESERVE a stored one — but it originates nothing, and a save carrying one would now hit
the 422 above.
No producer exists in this repo.
config: chartConfig.configat:2118/:2152were the only two occurrences of the pattern anywhere in the tree.
No stored fixture carries it. A structural scan (any object at key
chartowning aconfigkey, at any depth) over every tracked JSON file: 0 hits in objectui (544files parsed of 6485 tracked) and 0 in objectstack (444 parsed).
Legacy rows could in principle predate the #4001 tightening — which is exactly the risk the
next section bounds — but nothing measurable here produces or holds one.
Degrade, not break
packages/plugin-charts/src/ChartRenderer.tsx:151-160auto-generates a container configfrom
seriesplus a positional palette whenconfigis absent, so any non-conforming rowthat somehow existed still renders — it falls back to series-derived labels and default
chart colours. The spec's own refusal message says the same thing about the class:
Why nothing ever caught this, and why the casts went too
Not the
as any. One layer further out:ObjectChartis published as(props: any)(
packages/plugin-charts/src/ObjectChart.tsx:275, and verbatim in its.d.ts), so thoseliterals were checked against nothing whatever. MEASURED: with BOTH casts removed,
tsc --noEmitis green over a program--listFilesconfirms containsObjectView.tsx.The casts were inert. Leaving one sitting exactly where the defect lived is what invites
the next reader to assume the shape was checked, so they are gone with the rungs, and a
comment block records the reasoning in place.
That prop-type gap is one seam out and in two other packages, so it is reported, not fixed
here: objectui#7946.
The pin
ObjectView.chartConfigForward-7891.test.tsxreads the schemaObjectViewHANDS DOWN, onearm per branch, plus a positive control per branch so an absence assertion cannot go green
on a mount that rendered nothing. The assertion is
'config' in schema, nottoBeUndefined()— the removed line emitted a PRESENTconfig: undefinedkey on everychart view whether or not an author wrote one, so
toBeUndefined()would have passedagainst the defect itself.
Reverse verification, direction written before the run: re-injecting
config: chartConfig.config,into one literal was predicted to turn that branch's twoabsence arms RED and leave the other four arms green.
Tests 2 failed | 4 passed (6), the two failures being thedataset absence arms.
Tests 2 failed | 4 passed (6), the two failures being thelegacy absence arms.
Each leg confirmed the mutation on disk before reading (marker-count before/after, plus the
diff line), and each restored by STATE —
git diff HEADempty and the blob back to the HEADblob
ef1b7e36675ace83a3d55520149cbc2119a8b85b— never by an exit code. The legacy leg'sFIRST attempt refused to run: its marker text is a substring of the dataset branch's
more-indented copy, the anchor assertion caught the ambiguity, and the script reported
"mutation did NOT land on disk" instead of silently mutating the wrong branch. Re-anchored
on surrounding lines and re-run.
Verification, all at
e33c0c329vitest run packages/app-shell/(repo root,RUN v4.1.10 /home/user/objectui-issue-7891)Test Files 627 passed (627)·Tests 5995 passed, 1 skipped (5996)Test Files 2 passed (2)·Tests 14 passed (14)pnpm --filter @object-ui/app-shell run type-check(tsc --noEmitandtsc -p tsconfig.test.json)check:control-bytescheck:vi-mock-specifiers/check:vi-mock-inheritcheck:phantom-deps/check:self-import/check:esm-specifiers/check:unreferenced-sourcesnode scripts/check-changeset-presence.mjscheck-changeset-presence, verbatim:Lint — a declared narrowing, with its evidence.
eslint . --no-inline-configwas runwhole rather than narrowed: 4332 files linted, 0 errors in either changed file under a
configuration stricter than CI's (it disables the
eslint-disable-next-linecomments CIhonours). The 93 errors it reports are the repo's pre-existing baseline under that flag,
across 77 other files. The CI-equivalent targeted run on the two changed files is 0 errors,
172 warnings, all
no-explicit-any/react-refreshof the kind the lint workflowdeliberately does not cap. The config enables no type-aware linting (no
project/projectServiceineslint.config.js), so this diff cannot move any verdict on a file itdid not touch.
Scope
packages/app-shell/src/views/ObjectView.tsxplus one pin test in the same package, andthe changeset. Nothing in
packages/plugin-list/,packages/plugin-charts/,packages/types/, or the objectstack repo — which was read only. In particular noconfigrung was added to
ListView, and no published schema was changed: declaring the key wouldmint a second declaration of one that already exists, declared and documented, on the
standalone SDUI
type: 'chart'component(
packages/types/src/zod/sdui/data-display.zod.ts:664).Deleting a key the protocol already refuses by name changes no schema's accept/reject
behaviour, widens no public surface, and moves no gate's scan population — hence
Clause-②: no.Related, none of them addressed here: objectui#7823 and its PR only made this reachable
(before them the block did not arrive on that route with a usable binding at all, so this
was not a regression they introduced); objectui#7946 is the prop-type gap above.
🤖 Generated with Claude Code
Generated by Claude Code